package org.springblade.modules.admin.task.feishu;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.enums.FeiShuDocumentEnum;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.feishu.FeiShuBatchDTO;
import org.springblade.modules.admin.dto.feishu.FeiShuCreateBatchDTO;
import org.springblade.modules.admin.dto.feishu.FeiShuFieldsDTO;
import org.springblade.modules.admin.dto.feishu.UpdateMaintenancePersonnelDTO;
import org.springblade.modules.admin.enums.ComplianceStatusEnum;
import org.springblade.modules.admin.enums.ContractStatusEnum;
import org.springblade.modules.admin.enums.ElevatorMaintainStatusEnums;
import org.springblade.modules.admin.service.CompanyElevatorService;
import org.springblade.modules.admin.service.ElevatorService;
import org.springblade.modules.admin.service.feishu.IFeiShuDocumentService;
import org.springblade.modules.admin.vo.feishu.FeiShuQueryFieldsVO;
import org.springblade.modules.admin.vo.feishu.GovernmentElevatorPoolVO;
import org.springblade.modules.admin.vo.feishu.LarkMaintainPlanConfigVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 飞书云文档任务 电梯池
 *
 * @author: Sharry
 * @createTime: 2024-01-04 11:38
 * @version: Version-1.0
 */
@Component
@Slf4j
//@EnableScheduling
public class FeiShuDocumentPool {

	@Autowired
	private IFeiShuDocumentService feiShuDocumentService;

	@Autowired
	private ElevatorService elevatorService;

	@Autowired
	private CompanyElevatorService companyElevatorService;

	/**
	 * 定时任务：每7天2点30分执行一次
	 * 测试更新银河质监局电梯池
	 */
	@XxlJob("testGovernmentElevatorPool")
	public void testGovernmentElevatorPool() {
		XxlJobHelper.handleSuccess("定时任务更新银河租户质检院电梯池表格副本信息-[执行]开始");
		try{
			// 0. 更新流程：先列出全部记录，获取当前全部record_id 集合。现阶段先删除后新增，则完成更新
			String result = "";
			// 1. 数据准备：目标文件夹Token、文档ID; 需要更新的数据列表
			// 1.1 目标文件夹Token、文档ID
			String appToken = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_POOL_COPY.getAppToken();
			String tableId = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_POOL_COPY.getTableId();
			// 先处理历史数据
			feiShuDocumentService.commandDistinctByKeyAndUpdateTime(appToken, tableId, "设备注册代码","更新时间");
			// 1.2 分析网页数据
			// 发送get请求, 获取表数据
			String cselUrl = "http://120.24.168.16:18082/spider/galaxy/csel";
			HttpRequest.get(cselUrl).execute();

			// 1.3 表格数据去重，获取最新数据，且保证表里有数据
			companyElevatorService.distinctTableByDeviceCode();
			// 1.4 需要更新的数据列表
			List<GovernmentElevatorPoolVO> governmentElevatorPoolVOList = elevatorService.queryGovernmentElevatorPoolVOList();
			// 2. 数据处理；数据封装
			// 2.1 数据处理
			governmentElevatorPoolVOList = governmentElevatorPoolVOList.stream().filter(g ->
				!Func.isNull(g.getDeviceCode())
				&& Func.isNotBlank(g.getDeviceCode())
				&& !"/".equals(g.getDeviceCode())
			).collect(Collectors.toList());

			governmentElevatorPoolVOList.forEach(g -> {
				// 2.1.1 数据根据状态进行处理
				Integer fromType = g.getFromType();
				Integer maintainStatus = g.getMaintainStatus();
				if (new Integer("1").equals(fromType)) {
					g.setOutsourcingStatus("外包");
				} else if (new Integer("2").equals(fromType)) {
					g.setOutsourcingStatus("非外包");
				} else {
					g.setOutsourcingStatus("数据缺失");
				}
				// switch case 语句, maintainStatus -1:无状态，1: 脱保，2: 在保（合同期内），3：在保（合同期外），4：在保（拟定保养）
				switch (maintainStatus) {
					case -1:
						g.setInServiceStatus("无状态");
						break;
					case 1:
						g.setInServiceStatus("脱保");
						break;
					case 2:
						g.setInServiceStatus("在保（合同期内）");
						break;
					case 3:
						g.setInServiceStatus("在保（合同期外）");
						break;
					case 4:
						g.setInServiceStatus("在保（拟定保养）");
						break;
					default:
						g.setInServiceStatus("数据缺失");
						break;
				}
				// 2.1.2 计算日期
				String nextCheckTime = g.getNextCheckTime();
				// String 类型 的日期转换成 Date 类型
				Date nextCheckTimeDate = DateUtil.parse(nextCheckTime);
				// 计算从今天到目标日期的天数
				long days = DateUtil.betweenDay(new Date(), nextCheckTimeDate, false);
				g.setDaysToAnnualInspection(new Integer(String.valueOf(days)));
				Integer isQuaGuarantee = g.getIsQuaGuarantee();
				if(new Integer("1").equals(isQuaGuarantee)){
					g.setIsQuaGuaranteeDesc("质保合同");
				}else if(new Integer("0").equals(isQuaGuarantee)){
					g.setIsQuaGuaranteeDesc("非质保合同");
				}else if(new Integer("-1").equals(isQuaGuarantee)){
					g.setIsQuaGuaranteeDesc("无状态");
				}else {
					g.setIsQuaGuaranteeDesc("数据缺失");
				}
			});
			// 2.2 数据封装
			FeiShuCreateBatchDTO feiShuCreateBatchDTO = new FeiShuCreateBatchDTO();
			List<UpdateMaintenancePersonnelDTO> records = new ArrayList<>();
			for (GovernmentElevatorPoolVO u : governmentElevatorPoolVOList) {
				UpdateMaintenancePersonnelDTO element = new UpdateMaintenancePersonnelDTO();
				Map<String, Object> elementMap = new HashMap<>(10);
				elementMap.put("设备注册代码", u.getDeviceCode());
				elementMap.put("设备名称", u.getDeviceType());
				elementMap.put("使用证编号", u.getUseNum());
				elementMap.put("单位内部编号", u.getPrivateNum());
				elementMap.put("使用单位", u.getBuildingUser());
				elementMap.put("出厂编号", u.getCompanyNum());
				elementMap.put("定期报告编号", u.getReportNum());
				String nextCheckTime = u.getNextCheckTime();
				// String 类型 的日期转换成 long 类型
				if(Func.isNotBlank(nextCheckTime) && !Func.isNull(nextCheckTime)){
					try {
						long nextCheckTimeLong = DateUtil.parse(nextCheckTime).getTime();
						elementMap.put("下次定期检验日期", nextCheckTimeLong);
					}catch (Exception e){
						elementMap.put("下次定期检验日期", null);
						log.error(e.getMessage());
					}
				}
				elementMap.put("定期检验结论", u.getCheckResult());
				elementMap.put("使用状态", u.getUseStatus());
				elementMap.put("注册状态", u.getRegisterStatus());
				elementMap.put("所在地区", u.getLocation());
				elementMap.put("梯无忧-项目名称", u.getBuildingName());
				elementMap.put("梯无忧-梯号", u.getElevatorNum());
				elementMap.put("梯无忧_合同属性", u.getIsQuaGuaranteeDesc());
				elementMap.put("梯无忧-在保状态", u.getInServiceStatus());
				elementMap.put("梯无忧-外包情况", u.getOutsourcingStatus());
				elementMap.put("距离截止年审天数", u.getDaysToAnnualInspection());
				elementMap.put("梯无忧_合同服务时间(开始)",u.getContractBeginTime().getTime());
				elementMap.put("梯无忧_合同服务时间(结束)",u.getContractEndTime().getTime());
				elementMap.put("梯无忧_快速识别码",u.getElevatorFastNum());
				// 2024-05-06 新增字段
				elementMap.put("梯无忧_当前执行合同编号",u.getContractNo());
				if(!Func.isNull(u.getContractStatus())){
					Integer contractStatus = u.getContractStatus();
					String name = ContractStatusEnum.getName(contractStatus);
					elementMap.put("梯无忧_当前执行合同管理状态",name);
				}
				String link1 = "https://admin.sida-tech.com/#/contractManage/seeContract?id=";
				String link2 = "https://admin-test.sida-tech.com/#/contractManage/seeContract?id=";
				Map<String,String> linkMap = new HashMap<>(2);
				linkMap.put("link",link2 + u.getContractId());
				linkMap.put("text","梯无忧_合同详情页链接");
				elementMap.put("梯无忧_合同详情页链接",linkMap);
				/**
				 * 2024-06-17 新增省市区
				 */
				elementMap.put("省",u.getProvinceName());
				elementMap.put("市",u.getCityName());
				elementMap.put("区",u.getAdName());
				/**
				 * 2024-10-28 新增下次试验载荷时间
				 */
				if(!Func.isNull(u.getNextTestTime()) && Func.isNotBlank(u.getNextTestTime())){
					try{
						long nextTestTimeLong = DateUtil.parse(u.getNextTestTime()).getTime();
						elementMap.put("下次载荷试验日期",nextTestTimeLong);
					}catch (Exception e){
						elementMap.put("下次载荷试验日期",null);
					}
				}
				element.setFields(elementMap);
				records.add(element);
			}
			// records 去重
			Set<UpdateMaintenancePersonnelDTO> set = new HashSet<>(records);
			// 清空 records, 将 set 中的数据添加到 records 中
			records.clear();
			records.addAll(set);
			feiShuCreateBatchDTO.setRecords(records);
			result = feiShuDocumentService.commandCompareUpdateBatch( appToken, tableId,feiShuCreateBatchDTO,"设备注册代码");
			// 5. 发送消息, 通知到群
			List<JSONObject> targetGroupObjects = feiShuDocumentService.commandQueryGroupsBatch();
			List<String> chatIds = new ArrayList<>();
			targetGroupObjects.forEach(t -> chatIds.add(t.getString("chat_id")));
			// 发送消息
			String finalResult = result;
			chatIds.forEach(c -> {
				// 组装数据
				JSONObject bodyJson = new JSONObject();
				bodyJson.put("receive_id", c);
				bodyJson.put("msg_type", "text");
				HashMap<String, String> contentMap = new HashMap<>(2);
				String message = "定时任务更新银河租户质检院 电梯池表格副本信息，结果：" + finalResult;
				contentMap.put("text", message);
				// 将 contentMap 转换成 JSON 格式
				bodyJson.put("content", JSON.toJSONString(contentMap));
				feiShuDocumentService.commandSendGroupMessage(bodyJson.toJSONString());
			});
			XxlJobHelper.handleSuccess("定时任务更新银河租户质检院电梯池表格副本信息-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新银河租户质检院电梯池表格副本信息-[执行]失败"+e);
		}

	}

	/**
	 * 定时任务：每7天2点40分执行一次
	 * 更新银河质监局电梯池
	 */
	@XxlJob("governmentElevatorPool")
	public void governmentElevatorPool() {
		XxlJobHelper.handleSuccess("定时任务更新银河租户质检院电梯池表格信息-[执行]开始");
		try{
			// 0. 更新流程：先列出全部记录，获取当前全部record_id 集合。现阶段先删除后新增，则完成更新
			String result = "";
			// 1. 数据准备：目标文件夹Token、文档ID; 需要更新的数据列表
			// 1.1 目标文件夹Token、文档ID
			String appToken = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_POOL.getAppToken();
			String tableId = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_POOL.getTableId();
			// 先处理历史数据
			feiShuDocumentService.commandDistinctByKeyAndUpdateTime(appToken, tableId, "设备注册代码","更新时间");
			// 1.2 分析网页数据
//			String template = "http://wsbj2.gdsei.org.cn:8078/seimis/SbglAction.do?method=select_submit&ec_i=ec&eti=&eti_p=&ec_efn=&ec_ev=&ec_crd=100000&ec_f_a=&ec_p=1&ec_s_EQULOGCODE=&ec_s_EQUIPNAME=&ec_s_USECARNO=&ec_s_EQUORGNO=&ec_s_USEORGNAME=&ec_s_DNAME=&ec_s_EQULOCARECOD=&ec_s_PRONO=&ec_s_INSREPORTNO=&ec_s_NINSPDATE=&ec_s_INSRESULT=&ec_s_OYINSREPORTNO=&ec_s_OYNINSPDATE=&ec_s_OYINSRESULT=&ec_s_PRESOYINSREPORTNO=&ec_s_PRESNDATE=&ec_s_PRESRESULT=&ec_s_USSTATUS=&ec_s_LOGINSTATE=&LOGINSTATE=&USSTATUS=&type=&BUIORGNAME=&areacodecontent1=440000&EQUIPNAME=&areacodecontent2=&1704183545096=&EQUIPMODEL=&USECARNO=&PRONO=&STACHEORGUNICODE=&USEORGSYSNO=&EQUORGNO=&EQULOCARECOD=&JYJL_PARA=&USEORGNAME=&EQUCLACODE=&EQULOGCODE=&MAIORGNAME=&PORGAONAME=&method=select_submit&method=select_submit&ec_totalpages=1&ec_totalrows=&ec_f_radio=&ec_f_%E5%BA%8F%E5%8F%B7=&ec_f_EQULOGCODE=&ec_f_EQUIPNAME=&ec_f_USECARNO=&ec_f_EQUORGNO=&ec_f_USEORGNAME=&ec_f_DNAME=&ec_f_EQULOCARECOD=&ec_f_PRONO=&ec_f_INSREPORTNO=&ec_f_NINSPDATE=&ec_f_INSRESULT=&ec_f_OYINSREPORTNO=&ec_f_OYNINSPDATE=&ec_f_OYINSRESULT=&ec_f_PRESOYINSREPORTNO=&ec_f_PRESNDATE=&ec_f_PRESRESULT=&ec_f_USSTATUS=&ec_f_LOGINSTATE=&ec_pg=1&ec_rd=5&1704183552765";
//			List<String> urlList = Arrays.asList(template);
//			Spider spider1 = Spider.create(new GdseiPageProcessor(companyElevatorService))
//				.addPipeline(new MyPipeline(companyElevatorService));
//			for (String s : urlList) {
//				spider1.addUrl(s);
//			}
//			spider1.thread(25).run();
//			String url = "http://wsbj2.gdsei.org.cn:8078/seimis/jyjcWbfwHyAction.do?method=select";
//			String formData = "ec_i=ec&eti=&eti_p=&ec_efn=&ec_ev=&ec_crd=100&ec_f_a=&ec_p=1&ec_s_USEORGNAME=&ec_s_EQULOGCODE=&ec_s_USECARNO=&ec_s_EQUORGNO=&ec_s_AGENTCOMMENT=&ec_s_APPCONFMANNAME=&ec_s_PRONO=&ec_s_USSTATUS=&ec_s_ONLINELSH=&ec_s_APPNO=&ec_s_SEITESTSORT=&ec_s_EQUCLACODE=&ec_s_REPAIRAGREXTDATE=&ec_s_NINSPDATE=&ec_s_EQULOCARECOD=&ec_s_INSRESULT=&ec_s_MAIORGNAME=&1705459183135=&LOGINSTATE=1&USSTATUS=1&SYSFUNCODE=QYPT_ZZFW_DQSB&BUIORGNAME=&areacodecontent1=440000&EQUIPNAME=&areacodecontent2=&QYPT=1&1705458926456=&EQUIPMODEL=&USECARNO=&JYQKSTATE=&PRONO=&NINSPDATE_END=&STACHEORGUNICODE=&USEORGSYSNO=&EQUORGNO=&EQULOCARECOD=&USEORGNAME=%E6%B5%B7%E7%BA%B3%E7%99%BE%E5%B7%9D&EQULOGCODE=31104420002020010164&MAIORGNAME=&EQUCLACODE1=&PORGAONAME=&INSREPORTNO=&1705459154551=&1705458770060=&NINSPDATE_START=&1705458951105=&method=select&method=select&method=select&method=select&method=select&method=select&ec_totalpages=1&ec_totalrows=&ec_f_radio=&ec_f_%E5%BA%8F%E5%8F%B7=&ec_f_JYQK=&ec_f_USEORGNAME=&ec_f_EQULOGCODE=&ec_f_USECARNO=&ec_f_EQUORGNO=&ec_f_AGENTCOMMENT=&ec_f_APPCONFMANNAME=&ec_f_PRONO=&ec_f_USSTATUS=&ec_f_ONLINELSH=&ec_f_APPNO=&ec_f_SEITESTSORT=&ec_f_EQUCLACODE=&ec_f_REPAIRAGREXTDATE=&ec_f_NINSPDATE=&ec_f_EQULOCARECOD=&ec_f_INSRESULT=&ec_f_MAIORGNAME=&ec_pg=1&ec_rd=100&1705459199423";
//			url += "&" + formData;
//			Spider spider2 = Spider.create(new HnbcProcessor(companyElevatorService))
//				.addPipeline(new MyPipeline(companyElevatorService));
//			spider2.addUrl(url);
//			spider2.thread(25).run();

			// 发送get请求, 获取表数据
			String cselUrl = "http://120.24.168.16:18082/spider/galaxy/csel";
			HttpRequest.get(cselUrl).execute();

			// 1.3 表格数据去重，获取最新数据，且保证表里有数据
			companyElevatorService.distinctTableByDeviceCode();
			// 1.4 需要更新的数据列表
			List<GovernmentElevatorPoolVO> governmentElevatorPoolVOList = elevatorService.queryGovernmentElevatorPoolVOList();
			// 2. 数据处理；数据封装
			governmentElevatorPoolVOList = governmentElevatorPoolVOList.stream().filter(g ->
				!Func.isNull(g.getDeviceCode())
					&& Func.isNotBlank(g.getDeviceCode())
					&& !"/".equals(g.getDeviceCode())
			).collect(Collectors.toList());
			// 2.1 数据处理
			governmentElevatorPoolVOList.forEach(g -> {
				// 2.1.1 数据根据状态进行处理
				Integer fromType = g.getFromType();
				Integer maintainStatus = g.getMaintainStatus();
				if (new Integer("1").equals(fromType)) {
					g.setOutsourcingStatus("外包");
				} else if (new Integer("2").equals(fromType)) {
					g.setOutsourcingStatus("非外包");
				} else {
					g.setOutsourcingStatus("数据缺失");
				}
				// switch case 语句, maintainStatus -1:无状态，1: 脱保，2: 在保（合同期内），3：在保（合同期外），4：在保（拟定保养）
				switch (maintainStatus) {
					case -1:
						g.setInServiceStatus("无状态");
						break;
					case 1:
						g.setInServiceStatus("脱保");
						break;
					case 2:
						g.setInServiceStatus("在保（合同期内）");
						break;
					case 3:
						g.setInServiceStatus("在保（合同期外）");
						break;
					case 4:
						g.setInServiceStatus("在保（拟定保养）");
						break;
					default:
						g.setInServiceStatus("数据缺失");
						break;
				}
				// 2.1.2 计算日期
				String nextCheckTime = g.getNextCheckTime();
				// String 类型 的日期转换成 Date 类型
				Date nextCheckTimeDate = DateUtil.parse(nextCheckTime);
				// 计算从今天到目标日期的天数
				long days = DateUtil.betweenDay(new Date(), nextCheckTimeDate, false);
				g.setDaysToAnnualInspection(new Integer(String.valueOf(days)));
				Integer isQuaGuarantee = g.getIsQuaGuarantee();
				if(new Integer("1").equals(isQuaGuarantee)){
					g.setIsQuaGuaranteeDesc("质保合同");
				}else if(new Integer("0").equals(isQuaGuarantee)){
					g.setIsQuaGuaranteeDesc("非质保合同");
				}else if(new Integer("-1").equals(isQuaGuarantee)){
					g.setIsQuaGuaranteeDesc("无状态");
				}else {
					g.setIsQuaGuaranteeDesc("数据缺失");
				}
			});
			// 2.2 数据封装
			FeiShuCreateBatchDTO feiShuCreateBatchDTO = new FeiShuCreateBatchDTO();
			List<UpdateMaintenancePersonnelDTO> records = new ArrayList<>();
			for (GovernmentElevatorPoolVO u : governmentElevatorPoolVOList) {
				UpdateMaintenancePersonnelDTO element = new UpdateMaintenancePersonnelDTO();
				Map<String, Object> elementMap = new HashMap<>(10);
				elementMap.put("设备注册代码", u.getDeviceCode());
				elementMap.put("设备名称", u.getDeviceType());
				elementMap.put("使用证编号", u.getUseNum());
				elementMap.put("单位内部编号", u.getPrivateNum());
				elementMap.put("使用单位", u.getBuildingUser());
				elementMap.put("出厂编号", u.getCompanyNum());
				elementMap.put("定期报告编号", u.getReportNum());
				String nextCheckTime = u.getNextCheckTime();
				// String 类型 的日期转换成 long 类型
				if(Func.isNotBlank(nextCheckTime) && !Func.isNull(nextCheckTime)){
					try {
						long nextCheckTimeLong = DateUtil.parse(nextCheckTime).getTime();
						elementMap.put("下次定期检验日期", nextCheckTimeLong);
					}catch (Exception e){
						elementMap.put("下次定期检验日期", null);
						log.error(e.getMessage());
					}
				}
				elementMap.put("定期检验结论", u.getCheckResult());
				elementMap.put("使用状态", u.getUseStatus());
				elementMap.put("注册状态", u.getRegisterStatus());
				elementMap.put("所在地区", u.getLocation());
				elementMap.put("梯无忧_合同属性", u.getIsQuaGuaranteeDesc());
				elementMap.put("梯无忧-项目名称", u.getBuildingName());
				elementMap.put("梯无忧-梯号", u.getElevatorNum());
				elementMap.put("梯无忧-在保状态", u.getInServiceStatus());
				elementMap.put("梯无忧-外包情况", u.getOutsourcingStatus());
				elementMap.put("距离截止年审天数", u.getDaysToAnnualInspection());
				elementMap.put("梯无忧_合同服务时间(开始)",u.getContractBeginTime().getTime());
				elementMap.put("梯无忧_合同服务时间(结束)",u.getContractEndTime().getTime());
				elementMap.put("梯无忧_快速识别码",u.getElevatorFastNum());
				// 2024-05-06 新增字段
				elementMap.put("梯无忧_当前执行合同编号",u.getContractNo());
				if(!Func.isNull(u.getContractStatus())){
					Integer contractStatus = u.getContractStatus();
					String name = ContractStatusEnum.getName(contractStatus);
					elementMap.put("梯无忧_当前执行合同管理状态",name);
				}
				String link1 = "https://admin.sida-tech.com/#/contractManage/seeContract?id=";
				Map<String,String> linkMap = new HashMap<>(2);
				linkMap.put("link",link1 + u.getContractId());
				linkMap.put("text","梯无忧_合同详情页链接");
				elementMap.put("梯无忧_合同详情页链接",linkMap);
				/**
				 * 2024-06-17 新增省市区
				 */
				elementMap.put("省",u.getProvinceName());
				elementMap.put("市",u.getCityName());
				elementMap.put("区",u.getAdName());
				/**
				 * 2024-10-28 新增下次试验载荷时间
				 */
				if(!Func.isNull(u.getNextTestTime()) && Func.isNotBlank(u.getNextTestTime())){
					try{
						long nextTestTimeLong = DateUtil.parse(u.getNextTestTime()).getTime();
						elementMap.put("下次载荷试验日期",nextTestTimeLong);
					}catch (Exception e){
						elementMap.put("下次载荷试验日期",null);
					}
				}
				element.setFields(elementMap);
				records.add(element);
			}
			// records 去重
			Set<UpdateMaintenancePersonnelDTO> set = new HashSet<>(records);
			// 清空 records, 将 set 中的数据添加到 records 中
			records.clear();
			records.addAll(set);
			feiShuCreateBatchDTO.setRecords(records);
			result = feiShuDocumentService.commandCompareUpdateBatch(appToken, tableId,feiShuCreateBatchDTO,"设备注册代码");
			// 5. 发送消息, 通知到群
			List<JSONObject> targetGroupObjects = feiShuDocumentService.commandQueryGroupsBatch();
			List<String> chatIds = new ArrayList<>();
			targetGroupObjects.forEach(t -> chatIds.add(t.getString("chat_id")));
			// 发送消息
			String finalResult = result;
			chatIds.forEach(c -> {
				// 组装数据
				JSONObject bodyJson = new JSONObject();
				bodyJson.put("receive_id", c);
				bodyJson.put("msg_type", "text");
				HashMap<String, String> contentMap = new HashMap<>(2);
				String message = "定时任务更新银河租户质检院 电梯池表格信息，结果：" + finalResult;
				contentMap.put("text", message);
				// 将 contentMap 转换成 JSON 格式
				bodyJson.put("content", JSON.toJSONString(contentMap));
				feiShuDocumentService.commandSendGroupMessage(bodyJson.toJSONString());
			});
			XxlJobHelper.handleSuccess("定时任务更新银河租户质检院电梯池表格信息-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新银河租户质检院电梯池表格信息-[执行]失败"+e);
		}

	}

	/**
	 * 定时任务：在特检院电梯池结束后执行
	 * 副本
	 */
	@XxlJob("governmentUnMarkCopy")
	public void governmentUnMarkCopy() {
		XxlJobHelper.handleSuccess("定时任务更新凤仪的飞书电梯匹配失败表-[执行]开始");
		try{
			// 1. 数据准备：appToken、tableId、要覆盖的梯无忧列表
			String appToken = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_MATCH_FAILURE_COPY.getAppToken();
			String tableId = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_MATCH_FAILURE_COPY.getTableId();
			String searchAppToken = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_POOL.getAppToken();
			String searchTableId = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_POOL.getTableId();
			companyElevatorService.distinctTableByDeviceCode();
			List<GovernmentElevatorPoolVO> governmentElevatorPoolVOList = elevatorService.queryGovernmentElevatorPoolVOFull();

			// 1.1 获取当前飞书多维表格拥有的设备代码、数据库里的设备代码
			// 先处理格式不符的
			List<GovernmentElevatorPoolVO> failureList = governmentElevatorPoolVOList.stream().filter(g ->
				Func.isNull(g.getDeviceCode()) || !Func.isNotBlank(g.getDeviceCode()) || "/".equals(g.getDeviceCode())
			).collect(Collectors.toList());
			governmentElevatorPoolVOList = governmentElevatorPoolVOList.stream().filter(g ->
				!Func.isNull(g.getDeviceCode())
					&& Func.isNotBlank(g.getDeviceCode())
					&& !"/".equals(g.getDeviceCode())
			).collect(Collectors.toList());

			List<JSONObject> jsonObjects = feiShuDocumentService.commandQueryBatch(searchAppToken, searchTableId, null);
			List<FeiShuQueryFieldsVO> fromQuery = new ArrayList<>();
			jsonObjects.forEach(j -> fromQuery.add(j.toJavaObject(FeiShuQueryFieldsVO.class)));
			List<String> queryDeviceCodeList = new ArrayList<>();
			// 这步一定要保证 fromQuery 里设备注册代码全都有值
			fromQuery.forEach(f -> queryDeviceCodeList.add(f.getFields().get("设备注册代码").toString()));

			List<String> dbDeviceCodeList = governmentElevatorPoolVOList
				.stream()
				.map(GovernmentElevatorPoolVO::getDeviceCode)
				.collect(Collectors.toList());

			// failureList 为 dbDeviceCodeList 与 queryDeviceCodeList 差集
			if(Func.isEmpty(dbDeviceCodeList)){
				Set<String> dbSet = new HashSet<>(dbDeviceCodeList);
				for (String s : dbSet) {
					if(!queryDeviceCodeList.contains(s)){
						failureList.addAll(
							governmentElevatorPoolVOList.stream()
							.filter(g -> g.getDeviceCode().equals(s))
							.collect(Collectors.toList())
						);
					}
				}
			}
			// 2024-11-12 新增 failureList 新增 梯无忧有设备代码，且匹配不上爬取的设备代码情况
			List<String> markedDeviceCodeList = governmentElevatorPoolVOList
				.stream()
				.map(GovernmentElevatorPoolVO::getDeviceCode)
				.collect(Collectors.toList());
			List<GovernmentElevatorPoolVO> unMarkList = elevatorService.getUnMarkList(markedDeviceCodeList);
			failureList.addAll(unMarkList);
			// 2024-12-09 补全特检院有,但题无忧没有的信息
			List<GovernmentElevatorPoolVO> unFullList = elevatorService.getUnMarkListFull();
			failureList.addAll(unFullList);

			if(Func.isNotEmpty(failureList)){
				// 2. 数据处理、数据覆盖
				FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
				List<FeiShuFieldsDTO> records = new ArrayList<>();
				for (GovernmentElevatorPoolVO u : failureList) {
					FeiShuFieldsDTO element = new FeiShuFieldsDTO();
					Map<String, Object> elementMap = new HashMap<>(30);
					elementMap.put("设备注册代码", u.getDeviceCode());
					elementMap.put("设备名称", u.getDeviceType());
					elementMap.put("使用证编号", u.getUseNum());
					elementMap.put("单位内部编号", u.getPrivateNum());
					elementMap.put("使用单位", u.getBuildingUser());
					elementMap.put("出厂编号", u.getCompanyNum());
					elementMap.put("定期报告编号", u.getReportNum());
					String nextCheckTime = u.getNextCheckTime();
					// String 类型 的日期转换成 long 类型
					if(!Func.isBlank(nextCheckTime) && !Func.isNull(nextCheckTime)){
						// 处理掉所有不能parse 成date的情况
						try {
							long nextCheckTimeLong = DateUtil.parse(nextCheckTime).getTime();
							elementMap.put("下次定期检验日期", nextCheckTimeLong);
						} catch (Exception e) {
							elementMap.put("下次定期检验日期", null);
						}
					}
					elementMap.put("定期检验结论", u.getCheckResult());
					elementMap.put("使用状态", u.getUseStatus());
					elementMap.put("注册状态", u.getRegisterStatus());
					element.setFields(elementMap);
					records.add(element);
				}
				batchDTO.setRecords(records);

				List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
				// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
				List<String> r = new ArrayList<>();
				deleteObjects.forEach(j -> r.add(j.getString("record_id")));
				FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
				deleteFeiShuBatchDTO.setRecords(r);
				// 直接覆盖
				feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
				// 新增
				String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
				// 3. 发送飞书消息卡片到应用所在群聊
				String message = "覆盖"+FeiShuDocumentEnum.getDescription(appToken,tableId)+"结果：" + result;
				feiShuDocumentService.commandSendGroupMessage(appToken,tableId,message);
			}
			XxlJobHelper.handleSuccess("定时任务更新凤仪的飞书电梯匹配失败表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新凤仪的飞书电梯匹配失败表-[执行]失败"+e);
		}
	}

	/**
	 * 定时任务：在特检院电梯池结束后执行
	 * 正本
	 */
	@XxlJob("governmentUnMark")
	public void governmentUnMark() {
		XxlJobHelper.handleSuccess("定时任务更新凤仪的飞书电梯匹配失败表-[执行]开始");
		try{
			// 1. 数据准备：appToken、tableId、要覆盖的梯无忧列表
			String appToken = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_MATCH_FAILURE.getAppToken();
			String tableId = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_MATCH_FAILURE.getTableId();
			String searchAppToken = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_POOL.getAppToken();
			String searchTableId = FeiShuDocumentEnum.GOVERNMENT_ELEVATOR_POOL.getTableId();
			companyElevatorService.distinctTableByDeviceCode();
			List<GovernmentElevatorPoolVO> governmentElevatorPoolVOList = elevatorService.queryGovernmentElevatorPoolVOFull();

			// 1.1 获取当前飞书多维表格拥有的设备代码、数据库里的设备代码
			// 先处理格式不符的
			List<GovernmentElevatorPoolVO> failureList = governmentElevatorPoolVOList.stream().filter(g ->
				Func.isNull(g.getDeviceCode()) || !Func.isNotBlank(g.getDeviceCode()) || "/".equals(g.getDeviceCode())
			).collect(Collectors.toList());
			governmentElevatorPoolVOList = governmentElevatorPoolVOList.stream().filter(g ->
				!Func.isNull(g.getDeviceCode())
					&& Func.isNotBlank(g.getDeviceCode())
					&& !"/".equals(g.getDeviceCode())
			).collect(Collectors.toList());

			List<JSONObject> jsonObjects = feiShuDocumentService.commandQueryBatch(searchAppToken, searchTableId, null);
			List<FeiShuQueryFieldsVO> fromQuery = new ArrayList<>();
			jsonObjects.forEach(j -> fromQuery.add(j.toJavaObject(FeiShuQueryFieldsVO.class)));
			List<String> queryDeviceCodeList = new ArrayList<>();
			// 这步一定要保证 fromQuery 里设备注册代码全都有值
			fromQuery.forEach(f -> queryDeviceCodeList.add(f.getFields().get("设备注册代码").toString()));

			List<String> dbDeviceCodeList = governmentElevatorPoolVOList
				.stream()
				.map(GovernmentElevatorPoolVO::getDeviceCode)
				.collect(Collectors.toList());

			// failureList 为 dbDeviceCodeList 与 queryDeviceCodeList 差集
			if(Func.isEmpty(dbDeviceCodeList)){
				Set<String> dbSet = new HashSet<>(dbDeviceCodeList);
				for (String s : dbSet) {
					if(!queryDeviceCodeList.contains(s)){
						failureList.addAll(
							governmentElevatorPoolVOList.stream()
								.filter(g -> g.getDeviceCode().equals(s))
								.collect(Collectors.toList())
						);
					}
				}
			}
			// 2024-11-12 新增 failureList 新增 梯无忧有设备代码，且匹配不上爬取的设备代码情况
			List<String> markedDeviceCodeList = governmentElevatorPoolVOList
				.stream()
				.map(GovernmentElevatorPoolVO::getDeviceCode)
				.collect(Collectors.toList());
			List<GovernmentElevatorPoolVO> unMarkList = elevatorService.getUnMarkList(markedDeviceCodeList);
			failureList.addAll(unMarkList);
			// 2024-12-09 补全特检院有,但题无忧没有的信息
			List<GovernmentElevatorPoolVO> unFullList = elevatorService.getUnMarkListFull();
			failureList.addAll(unFullList);

			if(Func.isNotEmpty(failureList)){
				// 2. 数据处理、数据覆盖
				FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
				List<FeiShuFieldsDTO> records = new ArrayList<>();
				for (GovernmentElevatorPoolVO u : failureList) {
					FeiShuFieldsDTO element = new FeiShuFieldsDTO();
					Map<String, Object> elementMap = new HashMap<>(30);
					elementMap.put("设备注册代码", u.getDeviceCode());
					elementMap.put("设备名称", u.getDeviceType());
					elementMap.put("使用证编号", u.getUseNum());
					elementMap.put("单位内部编号", u.getPrivateNum());
					elementMap.put("使用单位", u.getBuildingUser());
					elementMap.put("出厂编号", u.getCompanyNum());
					elementMap.put("定期报告编号", u.getReportNum());
					String nextCheckTime = u.getNextCheckTime();
					// String 类型 的日期转换成 long 类型
					if(!Func.isBlank(nextCheckTime) && !Func.isNull(nextCheckTime)){
						// 处理掉所有不能parse 成date的情况
						try {
							long nextCheckTimeLong = DateUtil.parse(nextCheckTime).getTime();
							elementMap.put("下次定期检验日期", nextCheckTimeLong);
						} catch (Exception e) {
							elementMap.put("下次定期检验日期", null);
						}
					}
					elementMap.put("定期检验结论", u.getCheckResult());
					elementMap.put("使用状态", u.getUseStatus());
					elementMap.put("注册状态", u.getRegisterStatus());
					element.setFields(elementMap);
					records.add(element);
				}

				batchDTO.setRecords(records);
				List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
				// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
				List<String> r = new ArrayList<>();
				deleteObjects.forEach(j -> r.add(j.getString("record_id")));
				FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
				deleteFeiShuBatchDTO.setRecords(r);
				// 直接覆盖
				feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
				// 新增
				String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
				// 3. 发送飞书消息卡片到应用所在群聊
				String message = "覆盖"+FeiShuDocumentEnum.getDescription(appToken,tableId)+"结果：" + result;
				feiShuDocumentService.commandSendGroupMessage(appToken,tableId,message);
			}
			XxlJobHelper.handleSuccess("定时任务更新凤仪的飞书电梯匹配失败表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新凤仪的飞书电梯匹配失败表-[执行]失败"+e);
		}
	}

}
